Necesito llamar a this.getFact desde el componente Animal , pero usar this genera TypeError: this is undefined
import './App.css'; import React from 'react'; class App extends React.Component { constructor(props) { super(props); this.state = { fact: '', } } getFact(endpoint) { fetch(endpoint) .then(response => response.json()) .then(data => { this.setState({ fact: data.text, }); }) } Animal(props) { return ( <div> <h1>{props.name}</h1> <button onClick={() => this.getFact(props.endpoint)}>get a {props.name.toLowerCase()} fact</button> </div> ) } render() { return ( <div className="App"> <div> <p>{this.state.fact}</p> </div> <div className="animals"> <this.Animal name="Dog" endpoint="https://some-random-api.ml/facts/dog" /> <this.Animal name="Cat" endpoint="https://some-random-api.ml/facts/dog" /> <this.Animal name="Bird" endpoint="https://some-random-api.ml/facts/dog" /> <this.Animal name="Otter" endpoint="https://some-random-api.ml/facts/dog" /> </div> </div> ); } } export default App;Debe vincular ambas funciones (getFact y Animal) para poder usar esto dentro de la función Animal. En tu constructor haz esto:
constructor(props) { super(props); this.state = { fact: "" }; // Here you will bind the functions so they can be callable with this this.getFact = this.getFact.bind(this); this.Animal = this.Animal.bind(this); }Eso resolverá el problema, pero sugeriré mover el componente Animal fuera de su clase y pasar el getFact como accesorio. aún necesita vincular la función getFact, pero, sinceramente, reaccionará más y, a la larga, es más fácil de mantener. Algo como esto
function Animal(props) { return ( <div> <h1>{props.name}</h1> <button onClick={() => props.getFact(props.endpoint)}> get a {props.name.toLowerCase()} fact </button> </div> ); } class AppReactWay extends React.Component { constructor(props) { super(props); this.state = { fact: "" }; this.getFact = this.getFact.bind(this); } // Same code as you have render() { return ( <div className="App"> <div> <p>{this.state.fact}</p> </div> <div className="animals"> <Animal name="Dog" getFact={this.getFact} endpoint="https://some-random-api.ml/facts/dog" /> </div> </div> ); } } export default App;Además, después de verificar la respuesta de la API, debe modificar la función getFact, no es data.text, es data.fact.
getFact(endpoint) { fetch(endpoint) .then((response) => response.json()) .then(({ fact }) => { this.setState({ fact }); }); }Aquí hay una caja de arena de trabajo con ambos ejemplos.
El mejor enfoque sería llamar directamente a {this.Animal({ name: 'Dog', endpoint: 'https://some-random-api.ml/facts/dog'})} y así sucesivamente para cada animal.
El mejor enfoque sería que Animal tuviera su propio componente y pasara la función getFact como parámetro, no olvides que necesitarás vincularlo en ese caso o perderá este contexto.